package com.maiji.cloud.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.maiji.cloud.config.MyRedisConfig;
import com.maiji.cloud.entities.login.AppUser;
import com.maiji.cloud.entities.login.Label;
import com.maiji.cloud.entities.login.UploadRecord;
import com.maiji.cloud.entities.shopingmall.Goods;
import com.maiji.cloud.entities.shopingmall.GoodsUpdateLog;
import com.maiji.cloud.entities.shopingmall.LabelMiddleGoods;
import com.maiji.cloud.entities.shopingmall.ShopingOrder;
import com.maiji.cloud.mapper.GoodsMapper;
import com.maiji.cloud.microservice.LabelService;
import com.maiji.cloud.microservice.UploadRecordService;
import com.maiji.cloud.microservice.UserInfoService;
import com.maiji.cloud.request.ReqMetaData;
import com.maiji.cloud.request.login.UploadImageReqData;
import com.maiji.cloud.request.shopingmall.GoodsFindAllReqData;
import com.maiji.cloud.request.shopingmall.GoodsReqData;
import com.maiji.cloud.request.shopingmall.ParamConfigReqData;
import com.maiji.cloud.response.*;
import com.maiji.cloud.response.login.UploadImageResData;
import com.maiji.cloud.response.shopingmall.*;
import com.maiji.cloud.service.*;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.maiji.cloud.utils.*;
import org.apache.commons.lang.BooleanUtils;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Transactional
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {

    Logger logger = LoggerFactory.getLogger(GoodsServiceImpl.class);
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private GoodsCollectionService goodsCollectionService;
    @Autowired
    private UploadRecordService uploadRecordService;
    @Autowired
    private LabelMiddleGoodsService labelMiddleGoodsService;
    @Autowired
    private GoodsUpdateLogService goodsUpdateLogService;
    @Autowired
    private LabelService labelService;
    @Autowired
    private GoodsParamConfigService goodsParamConfigService;
    @Autowired
    private ShopingAddressService shopingAddressService;

    @Override
    public BaseResDto addGoods(GoodsReqData data) throws Exception {
        Goods goods = new Goods();
        BeanUtils.copyProperties(data, goods);
        String goodsId = UUID_MD5.getUUID();
        goods.setUuId(goodsId).setUpDate(new Date()).setUpdateDate(new Date());
        List<UploadRecord> dtUploadRecords = Lists.newArrayList();
        String detailText = DetailTextUtil.dealDetailText(MaijiOSS.OSSGOODSBUKET, goodsId, data.getDetailText(), dtUploadRecords);
        if (dtUploadRecords.size() > 0 && ! uploadRecordService.insertBatchUploadRecord(dtUploadRecords)) return new BaseResDto(Status.ERROR);
        if (! insert(goods.setDetailText(detailText))) new BaseResDto(Status.ERROR);
        List<ParamConfigReqData> goodsParams = data.getParams();
        if (goodsParams != null && goodsParams.size() > 0)
            if (! goodsParamConfigService.editGoodsParamByGoodsId(goodsId, goodsParams))
                return new BaseResDto(Status.ERROR.setMessage("保存商品参数失败"));
        GoodsUpdateLog goodsUpdateLog = new GoodsUpdateLog();
        BeanUtils.copyProperties(goods, goodsUpdateLog);
        List<UploadRecord> uploadRecords = data.getDetailImages().stream().map(image -> new UploadRecord()
                .setUuId(image.getUuId()).setBelongId(goodsId).setIsMain(image.getIsMain()).setNo(image.getNo())).collect(Collectors.toList());
        if (! uploadRecordService.updateBatchUploadRecord(uploadRecords)) return new BaseResDto(Status.ERROR);
        List<String> labelIds = data.getLabelIds();
        if (labelIds != null && labelIds.size() > 0) {
            List<LabelMiddleGoods> labelMiddleGoodsList = labelIds.stream().map(labelId ->
                    new LabelMiddleGoods().setUuId(UUID_MD5.getUUID()).setGoodsId(goodsId).setLabelId(labelId)).collect(Collectors.toList());
            if (! labelMiddleGoodsService.insertBatch(labelMiddleGoodsList)) return new BaseResDto(Status.ERROR);
        }
        String detailImagesIds = uploadRecords.stream().map(record -> record.getUuId() + ';').reduce("", String::concat);
        String labelIdsStr = labelIds.stream().map(labelId -> labelId + ";").reduce("", String::concat);
        goodsUpdateLog.setUuId(UUID_MD5.getUUID())
                .setGoodsId(goodsId)
                .setUpDown(1)
                .setUpdateUserId(data.getUserId())
                .setLabelIds(labelIdsStr)
                .setMainImageIds(uploadRecords.get(0).getUuId())
                .setDetailImageIds(detailImagesIds)
                .setUpdateExplain("添加商品");
        if (! goodsUpdateLogService.insert(goodsUpdateLog)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseResDto updateGoods(GoodsReqData goodsReqData) throws Exception {
        Goods goods = new Goods();
        BeanUtils.copyProperties(goodsReqData, goods);
        if (StringUtil.isBlank(goods.getUuId())) return new BaseResDto(Status.PARAMETERERROR);
        List<UploadRecord> uploadRecords = Lists.newArrayList();
        String detailText = DetailTextUtil.dealDetailText(MaijiOSS.OSSGOODSBUKET, goods.getUuId(), goodsReqData.getDetailText(), uploadRecords);
        if (uploadRecords.size() > 0) if (! uploadRecordService.insertBatchUploadRecord(uploadRecords)) return new BaseResDto(Status.ERROR);
        GoodsUpdateLog goodsUpdateLog = new GoodsUpdateLog();
        Integer upDown = goods.getUpDown();
        if (upDown == null) {
            goods.setUpdateDate(new Date());
            goodsUpdateLog.setUpdateExplain("修改商品数据");
        } else if (upDown == 1) {
            goods.setUpdateDate(new Date());
            goodsUpdateLog.setUpdateExplain("上架商品");
        } else if (upDown == 2) {
            goods.setDownDate(new Date());
            goodsUpdateLog.setUpdateExplain("下架商品");
        }
        if (! updateById(goods.setDetailText(detailText))) return new BaseResDto(Status.ERROR);
        List<ParamConfigReqData> goodsParams = goodsReqData.getParams();
        if (goodsParams != null && goodsParams.size() > 0) if (! goodsParamConfigService.editGoodsParamByGoodsId(
                goods.getUuId(), goodsParams)) return new BaseResDto(Status.ERROR.setMessage("保存商品参数失败"));
        BeanUtils.copyProperties(goods, goodsUpdateLog);
        goodsUpdateLog.setUuId(UUID_MD5.getUUID()).setUpdateUserId(goodsReqData.getUserId()).setGoodsId(goods.getUuId());
        if (! goodsUpdateLogService.insert(goodsUpdateLog)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseResDto updateGoodsLabels(String userId, String goodsId, List<String> delLabelIds, List<String> addLabelIds) {
        List<GoodsUpdateLog> goodsUpdateLogs = Lists.newArrayList();
        if (delLabelIds != null && delLabelIds.size() != 0){
            EntityWrapper<LabelMiddleGoods> entityWrapper = new EntityWrapper<>();
            entityWrapper.eq("goods_id", goodsId);
            entityWrapper.in("label_id", delLabelIds);
            if (! labelMiddleGoodsService.delete(entityWrapper))
                return new BaseResDto(Status.ERROR);
            String labelIdsStr = delLabelIds.stream().map(labelId -> labelId + ";").reduce("", String::concat);
            GoodsUpdateLog goodsUpdateLog = new GoodsUpdateLog();
            goodsUpdateLog.setUuId(UUID_MD5.getUUID())
                    .setUpdateUserId(userId)
                    .setGoodsId(goodsId)
                    .setUpdateDate(new Date())
                    .setLabelIds(labelIdsStr)
                    .setUpdateUserId(userId)
                    .setUpdateExplain("删除商品标签");
            goodsUpdateLogs.add(goodsUpdateLog);
        }
        if (addLabelIds != null && addLabelIds.size() != 0) {
            List<LabelMiddleGoods> labelMiddleGoodsList = addLabelIds.stream().map(labelId -> {
                LabelMiddleGoods labelMiddleGoods = new LabelMiddleGoods();
                labelMiddleGoods.setUuId(UUID_MD5.getUUID())
                        .setGoodsId(goodsId)
                        .setLabelId(labelId);
                return labelMiddleGoods;
            }).collect(Collectors.toList());
            if (! labelMiddleGoodsService.insertBatch(labelMiddleGoodsList))
                return new BaseResDto(Status.ERROR);
            String labelIdsStr = addLabelIds.stream().map(labelId -> labelId + ";").reduce("", String::concat);
            GoodsUpdateLog goodsUpdateLog = new GoodsUpdateLog();
            goodsUpdateLog.setUuId(UUID_MD5.getUUID())
                    .setGoodsId(goodsId)
                    .setUpdateDate(new Date())
                    .setLabelIds(labelIdsStr)
                    .setUpdateUserId(userId)
                    .setUpdateExplain("添加商品标签");
            goodsUpdateLogs.add(goodsUpdateLog);
        }
        if (goodsUpdateLogs.size() > 0) {
            if (! goodsUpdateLogService.insertBatch(goodsUpdateLogs)) return new BaseResDto(Status.ERROR);
            if (! updateById(new Goods().setUuId(goodsId).setUpdateDate(new Date()))) return new BaseResDto(Status.ERROR);
        }
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseResDto updateGoodsImages(String goodsId, List<UploadImageReqData> goodsCarouselImgs) {
//        if (! uploadRecordService.resetUploadRecord(goodsId)) return new BaseResDto(Status.ERROR);
        uploadRecordService.resetUploadRecord(goodsId, 1);
        List<UploadRecord> uploadRecords = goodsCarouselImgs.stream().map(img -> {
            UploadRecord uploadRecord = new UploadRecord();
            BeanUtils.copyProperties(img, uploadRecord);
            return uploadRecord.setBelongId(goodsId).setIsMain(1);
        }).collect(Collectors.toList());
        if (! uploadRecordService.updateBatchUploadRecord(uploadRecords)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseDataResDto<List<String>> findAllLabelsByGoodsId(String goodsId) {
        EntityWrapper<LabelMiddleGoods> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("goods_id", goodsId);
        List<String> labelIds = labelMiddleGoodsService.selectList(entityWrapper).stream()
                .map(lmg -> lmg.getLabelId())
                .collect(Collectors.toList());
        return new BaseDataResDto<List<String>>(Status.SUCCESS).setData(labelIds);
    }

    @Override
    public BaseDataResDto<GoodsResData> findGoodsById(String goodsId, String token) {
        GoodsResData goodsResData = findGoodsById(goodsId);
        if (goodsResData == null) return new BaseDataResDto<>(Status.PARAMETERERROR);
        if (StringUtil.isNotBlank(token)) {
            AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, token, userInfoService);
            goodsResData.setIsCollection(goodsCollectionService.isCollection(goodsId, appUser.getUuId()));
            //计算运费：使用用户默认收获地址，没有收货地址的使用全国范围规则计算运费
            ShopingOrderResData shopingOrderResData = new ShopingOrderResData();
            shopingAddressService.calculateFreight(shopingOrderResData, null, null, appUser.getUuId(), goodsResData.getPresentPrice(), goodsResData.getWeight(),false);
            goodsResData.setDeliveryFee(shopingOrderResData.getDeliveryFee());
        }
        return new BaseDataResDto<GoodsResData>(Status.SUCCESS).setData(goodsResData);
    }

    @Override
    public GoodsResData findGoodsById(String goodsId) {
        Goods goods = selectById(goodsId);
        if (goods == null) return null;
        GoodsResData goodsResData = new GoodsResData();
        BeanUtils.copyProperties(goods, goodsResData);
        goodsResData.setHint(CommonStringValueEnum.SHOPPING_HINT.getDescription());
        goodsResData.setNotice(CommonStringValueEnum.SHOPPING_NOTICE.getDescription());
        HashMap<String, Object> map = Maps.newHashMap();
        map.put("belongIds", Arrays.asList(goodsId));
        map.put("isMain", 1);
        map.put("orderBy", "no");
        map.put("isAsc", true);
        List<UploadImageResData> imageResDataList = uploadRecordService.findAllByBelongIds(map)
                .parallelStream().map(uploadRecord -> {
                    UploadImageResData uploadImageResData = new UploadImageResData();
                    BeanUtils.copyProperties(uploadRecord, uploadImageResData);
                    return uploadImageResData.setSmallUrl(uploadRecord.getUrl() + "?x-oss-process=image/resize,l_500");
                }).collect(Collectors.toList());
        if (imageResDataList.size() > 0) goodsResData.setMainImage(imageResDataList.get(0));
        goodsResData.setDetailImages(imageResDataList);
        return goodsResData;
    }

    @Override
    public BaseMetaResDto<List<GoodsResData>> findAllGoods(GoodsFindAllReqData data, ReqMetaData metaData, String token) {
        EntityWrapper<Goods> entityWrapper = new EntityWrapper<>();
        List<String> labelIds = data.getLabelIds();
        if (labelIds != null && labelIds.size() > 0) {
            Wrapper<LabelMiddleGoods> wrapper = new EntityWrapper<LabelMiddleGoods>().in("label_id", labelIds);
            List<String> goodsIds = labelMiddleGoodsService.selectList(wrapper)
                    .stream().map(LabelMiddleGoods::getGoodsId).collect(Collectors.toList());
            if (goodsIds.size() > 0) entityWrapper.in("uu_id", goodsIds);
        }
        List<String> goodsIds = data.getGoodsIds();
        if (goodsIds != null && goodsIds.size() > 0) entityWrapper.in("uu_id", goodsIds);
        if (StringUtil.isNotBlank(data.getName())) entityWrapper.like("name", data.getName());
        if (data.getUpDown() != 0) entityWrapper.eq("up_down", data.getUpDown());
        if (data.getIsExchange() != null) entityWrapper.eq("is_exchange", data.getIsExchange());
        BaseService.dealWithEntityWrapper(entityWrapper, data.getStockVolumes(), "stock_volume");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getOriginalPrices(), "original_price");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getPresentPrices(), "present_price");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getSalesVolumes(), "sales_volume");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getIntegrals(), "integrals");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getCollectionVolumes(), "collection_volume");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getCommentVolumes(), "comment_volume");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getUpDates(), "up_date");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getDownDates(), "down_date");
        BaseService.dealWithEntityWrapper(entityWrapper, data.getUpdateDates(), "update_date");
        if (BooleanUtils.isTrue(data.getShield())) entityWrapper.orderBy("comment_count", false);
        else entityWrapper.orderBy(data.getOrderBy(), data.getOrder().equals("asc")? true: false);
        Page<Goods> goodsPage = goodsService.selectPage(new Page<>(metaData.getPage(), metaData.getSize()), entityWrapper);
        List<GoodsResData> goodsResDataList = Lists.newArrayList();
        if (goodsPage.getRecords().size() > 0) goodsResDataList = findAllGoodsResData(goodsPage.getRecords(), token);
        ResMetaData resMetaData = new ResMetaData(goodsPage.getCurrent(), goodsPage.getSize(), goodsPage.getTotal());
        return new BaseMetaResDto<List<GoodsResData>>(Status.SUCCESS).setData(goodsResDataList).setResMetaData(resMetaData);
    }

    @Override
    public List<GoodsResData> findAllGoodsResData(List<Goods> goodsList, String token) {
        List<String> goodsIds = goodsList.stream().map(Goods::getUuId).collect(Collectors.toList());
        HashMap<String, Object> map = Maps.newHashMap();
        map.put("belongIds", goodsIds);
        map.put("isMain", 1);
        map.put("no", 0);
        List<GoodsResData> goodsResDataList = BaseService.dealWithOneToOne(goodsList, "getUuId", GoodsResData.class,
                "setMainImage", uploadRecordService.findAllByBelongIds(map), "getBelongId", UploadImageResData.class);
        if (StringUtil.isBlank(token)) return goodsResDataList;
        AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, token, userInfoService);
        logger.info("/GoodsServiceImpl/findAllGoodsResData/appUser ===>> {}", appUser);
        if (appUser == null) return goodsResDataList;
        return goodsResDataList.parallelStream().map(goodsResData ->
                goodsResData.setIsCollection(goodsCollectionService.isCollection(goodsResData.getUuId(), appUser.getUuId()))).collect(Collectors.toList());
    }

    @Override
    public BaseMetaResDto<List<GoodsResData>> findAllNewExchangeGoods(ReqMetaData metaData, String token) {
        Label label = labelService.selectOne("商品", "新品推荐");
        List<String> goodsIds = labelMiddleGoodsService.selectList(new EntityWrapper<LabelMiddleGoods>().eq("label_id", label.getUuId()))
                .parallelStream().map(LabelMiddleGoods::getGoodsId).collect(Collectors.toList());
        if (goodsIds.size() == 0) return new BaseMetaResDto(Status.SUCCESS).setData(Lists.newArrayList());
        EntityWrapper<Goods> entityWrapper = new EntityWrapper<>();
        entityWrapper.in("uu_id", goodsIds);
        entityWrapper.eq("up_down", 1);
        entityWrapper.gt("stock_volume", 0);
        entityWrapper.orderBy("sort_weight", false);
        Page<Goods> goodsPage = selectPage(new Page(metaData.getPage(), metaData.getSize()), entityWrapper);
        ResMetaData resMetaData = new ResMetaData(goodsPage.getCurrent(), goodsPage.getSize(), goodsPage.getTotal());
        List<Goods> goodsList = goodsPage.getRecords();
        if (goodsList.size() == 0) return new BaseMetaResDto<List<GoodsResData>>(Status.SUCCESS).setResMetaData(resMetaData);
        return new BaseMetaResDto<List<GoodsResData>>(Status.SUCCESS).setData(findAllGoodsResData(goodsList, token)).setResMetaData(resMetaData);
    }

    @Override
    public BaseMetaResDto<List<GoodsResData>> findAllGoodsByLabel(String goodsName, String labelName, ReqMetaData metaData, String token) {
        System.out.println("============================ GoodsServiceImpl >>>> " + Thread.currentThread().getName());
        Label label = labelService.selectOne("商品", labelName);
        List<String> selectedGoodsIds = labelMiddleGoodsService.selectList(new EntityWrapper<LabelMiddleGoods>().eq("label_id", label.getUuId()))
                .parallelStream().map(LabelMiddleGoods::getGoodsId).collect(Collectors.toList());
        List<Goods> selectedGoodsList = Lists.newArrayList();
        if (selectedGoodsIds.size() == 0 && StringUtil.isNotBlank(token)) return new BaseMetaResDto(Status.SUCCESS).setData(selectedGoodsList);
        if (selectedGoodsIds.size() > 0) {
            selectedGoodsList = goodsService.selectBatchIds(selectedGoodsIds).parallelStream().filter(goods -> {
                if (StringUtil.isBlank(goodsName)) return goods.getStockVolume() > 0 && goods.getUpDown() == 1;
                else return goods.getName().contains(goodsName) && goods.getStockVolume() > 0 && goods.getUpDown() == 1;
            }).sorted().collect(Collectors.toList());
        }
        if (metaData == null) return new BaseMetaResDto<List<GoodsResData>>(Status.SUCCESS).setData(findAllGoodsResData(selectedGoodsList, token));
        EntityWrapper<Goods> entityWrapper = new EntityWrapper<>();
        entityWrapper.notIn("uu_id", selectedGoodsIds);
        entityWrapper.gt("stock_volume", 0);
        entityWrapper.eq("up_down", 1);
        entityWrapper.orderBy("sort_weight", false);
        if (StringUtil.isNotBlank(goodsName)) entityWrapper.like("name", goodsName);
        List<Goods> notSelectedGoodsList = goodsService.selectList(entityWrapper);
        List<Goods> allGoodsList = Lists.newArrayList();
        allGoodsList.addAll(selectedGoodsList);
        allGoodsList.addAll(notSelectedGoodsList);
        Integer pageNo = metaData.getPage();
        Integer pageSize = metaData.getSize();
        Integer fromIndex = (pageNo - 1) * pageSize;
        Integer total = allGoodsList.size();
        List<GoodsResData> data = Lists.newArrayList();
        if (allGoodsList.size() > 0) {
            if (fromIndex >= total) return new BaseMetaResDto(Status.ERROR.setMessage("分页参数错误"));
            Integer toIndex = pageNo * pageSize;
            toIndex = toIndex < total ? toIndex : total;
            List<Goods> goodsList = allGoodsList.subList(fromIndex, toIndex);
            data = findAllGoodsResData(goodsList, token).stream().map(goodsResData -> {
                if (selectedGoodsIds.contains(goodsResData.getUuId()))
                    goodsResData.setIsRecommend(true).setIsNew(true).setIsPreferential(true);
                return goodsResData;
            }).collect(Collectors.toList());
        }
        ResMetaData resMetaData = new ResMetaData(pageNo, pageSize, Long.valueOf(total));
        return new BaseMetaResDto<List<GoodsResData>>(Status.SUCCESS).setData(data).setResMetaData(resMetaData);
    }

    @Override
    public BaseMetaResDto<List<GoodsResData>> findAllGoodsByFoodIds(List<String> foodIds, ReqMetaData reqMetaData) {
        Integer pageNo = reqMetaData.getPage();
        Integer pageSize = reqMetaData.getSize();
        Page<GoodsResData> page = new Page<>(pageNo, pageSize);
        List<GoodsResData> goodsList = goodsMapper.findAllGoodsByFoodId(foodIds, page);
        ResMetaData resMetaData = new ResMetaData(pageNo, pageSize, page.getTotal());
        return new BaseMetaResDto<List<GoodsResData>>(Status.SUCCESS).setData(goodsList).setResMetaData(resMetaData);
    }

    @Override
    public BaseDataResDto<Integer> IncreasestockVolumeCount(Integer min) {
        Wrapper<Goods> wrapper = new EntityWrapper<Goods>()
                .eq("up_down", 1)
                .lt("stock_volume", min);
        return new BaseDataResDto<Integer>(Status.SUCCESS).setData(selectCount(wrapper));
    }

}
